import QtQuick 2.0
import VPlay 2.0

EntityBase {
  entityType: "player"

  // the key-pressed-signals get emitted from the scene when key presses are detectedf
  // key pressed cant be detected here, because this item has no size
  signal leftPressed(variant event)
  signal rightPressed(variant event)
  signal upPressed(variant event)
  signal downPressed(variant event)

  signal died
  signal slowDownerCollision
  signal showText (string currentScore)

  // gets increased over time - it has the same value as the y value of the level
  property int score: 0

  // gets increased when a coin is collected
  property int bonusScore: 0

  // the total score is the one that gets displayed
  property int totalScore: score + (bonusScore * bonusScoreForCoin) + bigJumpScore

  // the total count of deaths within this gaming session
  property int deaths: 0

  // this gets added to bonusScore every time the player catches a coin
  property int bonusScoreForCoin: 300
  property int bigJumpScore: 0

  property alias controller: twoAxisController

  // these are the settings for balancing!
  property real upValue: 710
  property real upValueBooster: 900

  property real downValue: 5
  property real rightValue: 85
  property real rightValueAir: 200

  property real leftValue: -rightValue

  property real bigJumpThreshold: 100
  property real bigJumpVelXDivider: 700

  property date bigJumpStarted
  property bool bigJump: false
  property bool allowJump: false

  EditableComponent {
      editableType: "Player"
      properties : {
          "upValue": {"min": 200, "max": 1500, "label": "upValue"},
          "upValueBooster": {"min": 200, "max": 1500, "label": "upValueBooster"},
          "rightValue": {"min": 50, "max": 500, "label": "rightValue"},
          "rightValueAir": {"min": 50, "max": 500, "label": "rightValueAir"},
          "bigJumpThreshold": {"min": 50, "max": 1500, "label": "bigJumpThreshold"},
          "bigJumpVelXDivider": {"min": 50, "max": 1500, "label": "bigJumpVelXDivider"}
      }
  }
  //    property variant respawnPosition: Qt.point(50,100)

  // this is needed internally to find out if the image should be inverted
  property bool __isLookingRight: true

  // this is called when debugging and modifying values at runtime
  onRightValueChanged: console.debug("rightValue changed to", rightValue)

  // set the default pos to the respawnPosition
  //pos: respawnPosition

  // by setting this to true, the removeAllEntities() does not affect this entity, which is called from Level.stopGame()
  preventFromRemovalFromEntityManager: true

  Image {
    id: sprite
    source: "../../assets/img/front.png"
    anchors.centerIn: parent

    // only make the player half the size of a grid
    width: 20
    height: 20
    visible: false // will be visible in default state
  }

  Image {
    id: spriteMovement
    source: "../../assets/img/left.png"
    anchors.centerIn: parent
    mirror: __isLookingRight
    width: sprite.width
    height: sprite.height
    visible: false
  }

  Image {
    id: spriteFlying
    source: "../../assets/img/flying.png"
    anchors.centerIn: parent
    width: 25
    height: 20
    visible: false
  }

  ParticleVPlay{
        id: icyParticle

        // Particle location properties
        x: 0
        y: 10
        rotation: 90

        // start when finished loading
        autoStart: true
        fileName: "../particles/icy.json"
  }

  MovementAnimation {
      id: rotationAnim
      target: parent
      property: "rotation";
      velocity: collider.body.linearVelocity.x * 5
      running: true
  }

  // gets increased when a collision with a block occurs in onBeginContact, and decreased in onEndContact
  // when no blockCollisions happened, the fly-state is active!
  property int blockCollisions: 0

  BoxCollider {
    id: collider
    bodyType: Body.Dynamic
    fixedRotation: true

    // balancing settings:
    linearDamping: 5.0
    // set friction between 0 and 1
    friction: 0.6
    // restitution is bounciness - dont bounce, because then the state would be changed too often
    restitution: 0
    // the density normally gets calculated based on the dimensions of the body - it somehow has no effect!
    // if you want to make objects fall faster, increase gravity!
    // with higher density, the player doesnt bounce back from the blocks after jumping, as it is heavier
    //fixture.density: 100

    // this is needed, because otherwise when resetting the level (and the player position), and the body was sleeping before it wouldnt fall down immediately again, because it isnt woken up from sleeping!
   // sleepingAllowed: false

    //anchors.centerIn: parent
    anchors.fill: sprite
    //        width: sprite.width-3
    //        height: sprite.height-3

    //        radius: sprite.width/2

    fixture.onBeginContact: {
      var fixture = other;
      var body = fixture.parent;
      var component = body.parent;
      var collidedEntity = component.owningEntity;
      var collidedEntityType = collidedEntity.entityType;
        console.debug("Collided with " + collidedEntityType);

      if(collidedEntityType === "coin") {

        // the coin is pooled for better performance
        collidedEntity.removeEntity();

        // increase the score, and also play a pling sound
        bonusScore++;
        coinSound.play();
          player.showText("+ 300");

      } else if(collidedEntityType === "booster"){
          collider.body.linearVelocity.y += -upValueBooster;
          collidedEntity.removeEntity();
          if(!bigJump){
              startBigJump();
          }
          swooshSound.play();

          console.debug("Collided with booster");
      } else if(collidedEntityType === "slowdowner"){
          collidedEntity.removeEntity();
          console.debug("Collided with slowdowner");
          slowdownSound.play();
          player.slowDownerCollision();


      } else if(collidedEntityType === "platform") {
          console.debug("Player collision. contactNormal.x = " + Math.round(contactNormal.x) + "contactNormal.y = " + Math.round(contactNormal.y));
      } else if(collidedEntityType === "BorderWall"){
          // if player collides with wall, turn him around
          collider.linearVelocity.x *= -1;
      }
    }

    fixture.onEndContact: {
      var fixture = other;
      var body = fixture.parent;
      var component = body.parent;
      var collidedEntity = component.owningEntity;
      var collidedEntityType = collidedEntity.entityType;
      if(collidedEntityType === "platform") {
//
      }

    }
  }

  SoundEffectVPlay {
    id: coinSound
    source: "../snd/pling.wav"
  }

  SoundEffectVPlay {
    id: swooshSound
    source: "../snd/swoosh.wav"
  }

  SoundEffectVPlay {
    id: slowdownSound
    source: "../snd/slowdown.wav"
  }

  TwoAxisController {
    id: twoAxisController

    onXAxisChanged: {
      if(xAxis>0){
        __isLookingRight = true;
      }else if(xAxis<0){
        __isLookingRight = false;
      }
    }
  }

  function allowJumping(allow){
      if(allow){
          blockCollisions++;
      } else {
          blockCollisions--;
      }

      if(blockCollisions < 0){
          blockCollisions = 0;
      }

//      console.debug("Player::allowJumping called, allow = " + allow);
//      console.debug("Player::blockCollisions = " + blockCollisions);

      if(blockCollisions >= 1){
          if(bigJump){
              bigJump = false;
              var now = new Date();
              var currentScore = Math.round(Math.abs(now.getMilliseconds() - bigJumpStarted.getMilliseconds()) / 10);
              player.bigJumpScore += currentScore;
              player.showText("+ " + currentScore);
              console.debug(Math.abs(now.getMilliseconds() - bigJumpStarted.getMilliseconds()) + " points added for bigjump!");
          }
          allowJump = true;
      } else {
          allowJump = false;
      }

//      console.debug("Player::blockCollisions new = " + blockCollisions);

  }

  function startBigJump(){
      // the faster the player, the higher the jump :)
      console.debug("BIG FUCKING JUMP")
      bigJump = true;
      bigJumpStarted = new Date();
      rotationAnim.start();
  }

  Timer {
    id: updateTimer
    interval: 60
    running: true
    repeat: true
    onTriggered: {

      // this must be done every frame, because the linearVelocity gets reduced because of the damping!
      var xAxis = controller.xAxis;
      if(xAxis) {
          if(allowJump){
                collider.body.linearVelocity.x += xAxis * rightValue;
          } else {
                collider.body.linearVelocity.x = xAxis * rightValueAir;
          }
      }

      var yAxis = controller.yAxis;

      // jump if a press occurs and the player is currently standing on a platform
      var velY = collider.body.linearVelocity.y;
      if(allowJump && yAxis){
          // if player is faster than usual
          if(Math.abs(collider.body.linearVelocity.x) > bigJumpThreshold) {
              var velX = collider.body.linearVelocity.x;
              velX = Math.abs(velX) / bigJumpVelXDivider;
             // console.debug(velX, "<--- velX");
              collider.body.linearVelocity.y = yAxis * -upValue * (1 + velX);
              startBigJump();
          } else {
              collider.body.linearVelocity.y = yAxis * -upValue;
          }
      }

      if(bigJump && __isLookingRight){
        icyParticle.gravity = Qt.point(0,-1000);
        icyParticle.start();
          rotationAnim.start();
      } else if(bigJump && !__isLookingRight){
         icyParticle.gravity = Qt.point(0,1000);
         icyParticle.start();
         rotationAnim.start();
      } else {
          icyParticle.stop();
          rotationAnim.stop();
          rotation = 0;
      }
    }
  }

  state: {
    if(blockCollisions==0)
      return "fly";
    else {
      if(controller.xAxis !== 0) {
        return "moveLeftRight";
      }
      return "";
    }
  }

  states: [
    State {
      name: ""
      PropertyChanges { target: sprite; visible: true }
      PropertyChanges { target: spriteFlying; visible: false }
      PropertyChanges { target: spriteMovement; visible: false }
    },
    State {
      name: "fly"
      PropertyChanges { target: sprite; visible: false }
      PropertyChanges { target: spriteFlying; visible: true }
      PropertyChanges { target: spriteMovement; visible: false }
     },
    State {
      name: "moveLeftRight"
      PropertyChanges { target: sprite; visible: false }
      PropertyChanges { target: spriteFlying; visible: false }
      PropertyChanges { target: spriteMovement; visible: true }
     }
  ]
}
